<template>
  <view :class="[`mx-${props.margin[0]}`]">
    <tm-sheet
      :transprent="props.transprent !== null ? props.transprent : tmFormTransprent"
      :round="props.round"
      :margin="[0, 0]"
      :padding="props.padding"
    >
      <view :class="[`py-${props.margin[1]}`]">
        <view
          v-if="props.showError && props.showTopErrorGap"
          :style="{ height: `${props.errHeight}rpx` }"
        >
        </view>
        <view
          :class="[
            'flex',
            tmFormLayout == 'horizontal' ? 'flex-row ' : ' ',
            tmFormLayout == 'horizontal' && !props.align ? 'flex-row-center-start' : '',
			<!-- #ifndef APP-NVUE -->
            tmFormLayout == 'vertical' && !props.align ? 'flex-col' : '',
			<!-- #endif -->
            props.align,
            props.parentClass,
          ]"
        >
          <slot name="label">
            <view
              v-if="_label"
              :style="[
                tmFormLayout == 'horizontal'
                  ? { width: (props.labelWidth || tmFormLabelWidth) + 'rpx' }
                  : '',
              ]"
              class="flex flex-row"
              :class="[
                tmFormLabelAlign == 'right' ? 'flex-row-center-end' : 'flex-row-center-start',
                tmFormLayout != 'horizontal' ? 'mb-24 flex-1 ' : 'mr-32 ',
              ]"
            >
              <view
                v-if="tmFormLabelAlign != 'right'"
                style="width: 12px"
                class="flex flex-row flex-row-center-center"
              >
                <tm-text v-if="_required" color="red" :font-size="30" label="*"></tm-text>
              </view>
              <view
                class="flex"
                :class="[
                  tmFormLayout == 'horizontal' ? 'flex-1' : '',
                  tmFormLabelAlign == 'right' && tmFormLayout == 'horizontal'
                    ? 'text-align-right'
                    : '',
                  tmFormLabelAlign == 'center' && tmFormLayout == 'horizontal'
                    ? 'text-align-center'
                    : '',
                ]"
                :style="[tmFormLayout == 'horizontal' ? { width: '0px' } : '']"
              >
                <tm-text
                  :color="
                    tmFormFun == 'validate' &&
                    item.isRequiredError == true &&
                    props.requiredTitleChangeColor
                      ? 'red'
                      : ''
                  "
                  :font-size="30"
                  :label="_label"
                ></tm-text>
              </view>
              <view
                v-if="tmFormLabelAlign == 'right'"
                style="width: 12px"
                class="flex flex-row flex-row-center-center"
              >
                <tm-text v-if="_required" color="red" :font-size="30" label="*"></tm-text>
              </view>
            </view>
          </slot>
          <view class="flex-1" :style="[tmFormLayout == 'horizontal' ? { width: '0px' } : '']">
            <slot></slot>
          </view>
        </view>
        <view :class="props.desc ? 'pt-12' : ''">
          <slot name="desc">
            <tm-text color="grey-darken-2" :font-size="22" :label="props.desc"></tm-text>
          </slot>
        </view>
        <view v-if="props.showError" :style="{ height: `${props.errHeight}rpx` }">
          <view v-if="tmFormFun == 'validate' && item.isRequiredError == true">
            <slot name="error" :data="{ message: item.message }">
              <tm-text color="red" :font-size="22" :label="item.message"></tm-text>
            </slot>
          </view>
        </view>
      </view>
    </tm-sheet>
    <view v-if="tmFormBorder">
      <tm-divider :border="2" :padding="[0, 0]" :margin="[0, 0]"></tm-divider>
    </view>
  </view>
</template>
<script lang="ts" setup>
  /**
   * 表单项目
   * @description 只能放置在tm-from里面，不限层级。但不能嵌套使用。
   * 从3.0.86开始,验证不与子组件挂勾,只验证绑定到form中的vmodel数据中的formitem中的filed字段.
   * 这样的改变意味着,传统的cell或者只用展示的view组件,只要提供了filed就能验证,无需特定Input,upload这样的
   * 组件才能进行验证.大大的提高了移动端的表单验证效率,特别适合大量的不同类型数据组件的验证规则.
   */
  import {
    computed,
    watch,
    PropType,
    provide,
    ref,
    getCurrentInstance,
    onUnmounted,
    Ref,
    inject,
    isProxy,
    toRaw,
    ComputedRef,
    onMounted,
    nextTick,
  } from 'vue';
  import tmSheet from '../tm-sheet/tm-sheet.vue';
  import tmText from '../tm-text/tm-text.vue';
  import tmDivider from '../tm-divider/tm-divider.vue';
  import { rulesItem, inputPushItem } from './interface';
  import { formItem, validateResultListType } from './../tm-form/interface';
  const proxy = getCurrentInstance()?.proxy ?? null;
  const tmFormComnameFormItem = 'tmFormComnameFormItem';
  const props = defineProps({
    parentClass: {
      type: String,
      default: '',
    },
    align: {
      type: String,
      default: '',
    },
    label: {
      type: String,
      default: '',
    },
    //表单描述
    desc: {
      type: String,
      default: '',
    },
    margin: {
      type: Array as PropType<Array<number>>,
      default: () => [12, 12],
    },
    padding: {
      type: Array as PropType<Array<number>>,
      default: () => [0, 0],
    },
    //如果在forom绑定的model为深层对象，这里的名称需要如下:
    //比如model = {a:2,b:{c:333}}
    //如果想绑定c,则field = "b.c"
    field: {
      type: String,
      default: '',
    },
    //表彰底部的单项注意说明。
    help: {
      type: String,
      default: '',
    },
    //是否必填
    required: {
      type: Boolean,
      default: false,
    },
    //检验规则
    rules: {
      type: [Object, Array] as PropType<Array<rulesItem> | rulesItem>,
      default: () => {
        return [{ validator: false, required: false }];
      },
    },
    //显示下划线。
    border: {
      type: Boolean,
      default: null,
    },
    showError: {
      type: Boolean,
      default: true,
    },
    /**当显示错误信息标题时，是否隐藏顶部的间隙，当连续的布局时有用，可以减少之间的间隙大小。 */
    showTopErrorGap: {
      type: Boolean,
      default: true,
    },
    //校验不通过时，是否让标题跟着变化文字颜色，默认是。
    requiredTitleChangeColor: {
      type: Boolean,
      default: false,
    },
    transprent: {
      type: [Boolean, String],
      default: null,
    },
    round: {
      type: Number,
      default: 0,
    },
    errHeight: {
      type: Number,
      default: 30,
    },
    labelWidth: {
      type: Number,
      default: 0,
    },
  });
  const item = ref<formItem>({
    label: '', //标签名称。
    field: props.field, //字段名称key.
    value: null,
    isRequiredError: false, //true,错误，false正常 检验状态
    message: '', //检验信息提示语。
    id: uni.$tm.u.getUid(1), //表单唯一标识id
    componentsName: '', //表单组件类型。
    rules: [],
  });
  const _required = ref(props.required);
  const tmFormLabelWidth = inject(
    'tmFormLabelWidth',
    computed(() => 100),
  );
  const tmFormLabelAlign = inject(
    'tmFormLabelAlign',
    computed(() => 'left'),
  );
  const tmFormLayout = inject(
    'tmFormLayout',
    computed(() => 'horizontal'),
  );
  const tmFormBorder_inject = inject(
    'tmFormBorder',
    computed(() => true),
  );
  const tmFormTransprent = inject(
    'tmFormTransprent',
    computed(() => false),
  );
  const tmFormFun = inject(
    'tmFormFun',
    computed(() => ''),
  );
  const tmFormValidateResultList = inject(
    'validateResultList',
    computed<validateResultListType[]>(() => []),
  );

  const tmFormBorder = computed(() => {
    if (props.border !== null && typeof props.border === 'boolean') return props.border;
    return tmFormBorder_inject.value;
  });
  const _label = computed(() => props.label);
  //父级方法。
  let parent: any = proxy?.$parent;
  while (parent) {
    if (parent?.tmFormComnameId == 'tmFormId' || !parent) {
      break;
    } else {
      parent = parent?.$parent ?? undefined;
    }
  }

  //卸载后需要清空。
  onUnmounted(() => {
    delCom();
  });

  // provide("tmFormItemVaildata",item.value.isRequiredError)
  const Rules = computed(() => {
    let defaultrs: Array<rulesItem> = [];
    if (Array.isArray(props?.rules)) {
      props?.rules.forEach((el) => {
        let isreq = el?.required || props.required;
        defaultrs.push({
          message: el?.message ?? '请填写必要的内容',
          required: isreq,
          validator: el?.validator ?? false,
        });
      });
    } else {
      defaultrs = [
        {
          message: props?.rules?.message ?? '请填写必要的内容',
          required: props.rules?.required || props.required,
          validator: props.rules?.validator ?? false,
        },
      ];
    }
    return defaultrs;
  });
  //向父级推表单类组件。
  function pushCom(itemComval?: inputPushItem) {
    if (parent) {
      item.value = { ...item.value, ...(itemComval ?? {}), rules: Rules.value };
      parent.pushKey({ ...item.value });
    }
  }
  function delCom() {
    if (parent) {
      parent.delKey(item.value);
    }
  }

  defineExpose({ pushCom, delCom, tmFormComnameFormItem });

  const validate = (rules: Array<rulesItem>, value: any) => {
    rules = rules.map((el) => {
      if (typeof el.validator === 'function' && el.required === true) {
        return el;
      } else if (typeof el.validator === 'boolean' && el.required === true) {
        return {
          ...el,
          validator: (val: any) => {
            if (val === null || val === '' || typeof val == 'undefined') return false;
            if (typeof val === 'object') {
              if (Array.isArray(val)) {
                if (val.length == 0) return false;
              } else if (Object.keys(val).length === 0 && val.constructor === Object) {
                return false;
              }
            }
            if (typeof val === 'boolean') {
              return val;
            }
            if (typeof val === 'number') {
              if (isNaN(val)) return false;
              if (Number(val) < 0) return false;
            }
            if (typeof val === 'string') {
              if (val.trim().length == 0) return false;
            }
            return true;
          },
        };
      } else {
        return {
          ...el,
          validator: (val: string | number) => {
            return true;
          },
        };
      }
    });
    let rules_filter: Array<rulesItem> = rules.filter((el) => {
      return typeof el.validator === 'function' && el.required === true;
    });
    let rules_fun: Array<Promise<rulesItem>> = rules_filter.map((el) => {
      return new Promise(async (res, rej) => {
        if (typeof el.validator === 'function') {
          let vr = await el.validator(value);
          if (vr) {
            res({
              message: String(el.message),
              validator: true,
            });
          } else {
            rej({
              message: el.message,
              validator: false,
            });
          }
        } else {
          res({
            message: el.message,
            validator: true,
          });
        }
      });
    });

    return Promise.all(rules_fun);
  };

  onMounted(() => {
    //预先推送。
    pushCom();
  });

  watch(
    () => tmFormValidateResultList.value,
    () => {
      const result = tmFormValidateResultList.value.filter((el) => el.field == props.field);
      if (result.length > 0) {
        item.value.message = result[0].message;
        item.value.isRequiredError = !result[0].validator;
      }
    },
    { deep: true, immediate: true },
  );

  function _recursive_parseJson2Form_(resObj: any, parentKey: string, JsonObject: any) {
    var gettype = Object.prototype.toString;
    for (var Key in JsonObject) {
      var tmpVal = JsonObject[Key];

      var typeStr = gettype.call(tmpVal);
      /*
	
								"[object String]";
								"[object Number]";
								"[object Boolean]"
								"[object Undefined]"
								"[object Null]"
								"[object Object]"
								"[object Array]"
								"[object Function]"
								*/
      if (tmpVal == null || tmpVal == undefined) {
        resObj[parentKey + '.' + Key] = '';
      } else {
        if (
          typeStr == '[object String]' ||
          typeStr == '[object Number]' ||
          typeStr == '[object Boolean]' ||
          typeStr == '[object Null]' ||
          typeStr == '[object Undefined]'
        ) {
          resObj[parentKey + '.' + Key] = tmpVal + '';
        } else if (typeStr == '[object Object]') {
          _recursive_parseJson2Form_(resObj, parentKey + '.' + Key, tmpVal);
        } else if (typeStr == '[object Array]') {
          if (tmpVal.length <= 0) {
            resObj[parentKey + '.' + Key] = '';
          } else {
            var isSimpleArray = false;
            for (var arrIndex in tmpVal) {
              var childItem = tmpVal[arrIndex];
              var childTypeStr = gettype.call(childItem);

              if (
                childTypeStr == '[object String]' ||
                childTypeStr == '[object Number]' ||
                childTypeStr == '[object Boolean]' ||
                childTypeStr == '[object Null]' ||
                childTypeStr == '[object Undefined]'
              ) {
                isSimpleArray = true;
              }
            }
            if (isSimpleArray) {
              resObj[parentKey + '.' + Key] = tmpVal.join(',');
            } else {
              var nowIndex = 0;
              for (var arrIndex in tmpVal) {
                var childItem = tmpVal[arrIndex];
                _recursive_parseJson2Form_(
                  resObj,
                  parentKey + '.' + Key + '[' + nowIndex + ']',
                  childItem,
                );
                nowIndex++;
              }
            }
          }
        }
      }
    }
  }
</script>

<style></style>
